介绍USB系统框架,只关注框架部分,不涉及细节

USB设备注册过程

usb_add_hcd -> register_root_hub -> usb_new_device -> device_add(添加设备) ->
usb_device_match(驱动匹配) -> generic_probe -> usb_set_configuration -> device_add(添加接口) ->
usb_device_match(ID 匹配) -> usb接口驱动的probe

USB初始化

usb_int

usb_int初始化整个usb系统的基础部分

  1. 注册USB总线
    bus_register(&usb_bus_type);
  2. 注册usbfs驱动
    usb_register(&usbfs_driver);
  3. 注册usb hub驱动
    usb_hub_init -> usb_register(&hub_driver)
  4. 注册通用设备驱动
    usb_register_device_driver(&usb_generic_driver, THIS_MODULE)

host总线初始化

以msm ehci为例

  1. 初始化echi驱动数据结构
    ehci_init_driver(&msm_hc_driver, &msm_overrides);

    使用ehci_hc_driver数据结构为基础
    
  2. 创建hcd

    1
    2
    hcd = usb_create_hcd(&msm_hc_driver, &pdev->dev,
    dev_name(&pdev->dev));

​ 其中msm_hc_driver在上一步初始化,以ehci_hc_driver为基础
重点:hcd->self是一条usb总线

1
2
3
struct usb_hcd {
struct usb_bus self; /* hcd is-a bus */
......
  1. 添加hcd到系统中
    usb_add_hcd(hcd, hcd->irq, IRQF_SHARED)

    • 向usb系统中注册一条总线
      usb_register_bus(&hcd->self))
    • 创建一个USB设备,作为根hub
      rhdev = usb_alloc_dev(NULL, &hcd->self, 0)
      hcd->self.root_hub = rhdev
      详见:usb设备创建
    • 为该总线注册根hub
      register_root_hub(hcd)
  2. 根hub注册过程

    1. 获取根hub的描述信息
      usb_get_device_descriptor(usb_dev, USB_DT_DEVICE_SIZE);

    2. 向usb系统中添加了一个usb设备:usb_new_device (usb_dev);

      该设备是上一步创建的根hub设备struct usb_device \usb_dev = hcd->self.root_hub;*

usb设备创建

usb_alloc_dev(struct usb_device parent,
struct usb_bus
bus, unsigned port1)

设备类型:

1
2
3
4
5
6
dev->dev.bus = &usb_bus_type;
dev->dev.type = &usb_device_type;
...
if (unlikely(!parent)) {
root_hub = 1;
}

设备路径&设备名字:

​ 根hub:很简单,路径为”0”, 名字直接是总线编号
​ dev->devpath[0] = ‘0’;
​ dev_set_name(&dev->dev, “usb%d”, bus->busnum);

​ 普通设备
​ hub设备自身(父设备为根hub):路径为端口编号
​ snprintf(dev->devpath, sizeof dev->devpath, “%d”, port1);

​ 普通设备(父设备为hub设备):路径为hub路径+端口编号
​ snprintf(dev->devpath, sizeof dev->devpath,”%s.%d”, parent->devpath, port1);

​ 设备名字:总线编号 + 设备路径
​ dev_set_name(&dev->dev, “%d-%s”, bus->busnum, dev->devpath);

usb添加设备

int usb_new_device(struct usb_device *udev)

  1. USB枚举设备
    usb_enumerate_device(udev)
    获取USB配置:usb_get_configuration(udev)

  2. 显示usb设备信息
    announce_device(udev);

  3. 添加设备
    device_add(&udev->dev)
    重点:会触发probe

  4. 创建endpoint设备
    usb_create_ep_devs(&udev->dev, &udev->ep0, udev)

    1
    2
    3
    4
    5
    6
    ep_dev->udev = udev;
    ep_dev->dev.groups = ep_dev_groups;
    ep_dev->dev.type = &usb_ep_device_type;
    ep_dev->dev.parent = parent;
    dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress);
    device_register(&ep_dev->dev);

usb probe过程

  1. 查找驱动
    usb_device_match
  2. usb设备probe:generic_probe
    选择配置:usb_choose_configuration
    设置配置:usb_set_configuration (重点
  3. usb接口probe:
    配置id表:usb驱动的id_table
    usb_match_id(intf, usb_drv->id_table)
    
    动态匹配(非常有用

usb 动态匹配表

usb probe过程中,优先使用静态表(代码中写死,编译后不可更改),如果静态表中没有当前设备(usb 接口)则使用动态表

动态表由应用层写入
路径:/sys/bus/usb/driver/\/new_id
格式:\ \ [InterfaceClass [refVendor refProduct]]

usb 设置配置

usb_set_configuration

遍历当前配置的接口(通过usb_get_configuration从usb设备获取)

1
2
3
4
5
intf->dev.bus = &usb_bus_type;
intf->dev.type = &usb_if_device_type;
dev_set_name(&intf->dev, "%d-%s:%d.%d",
dev->bus->busnum, dev->devpath,
configuration, alt->desc.bInterfaceNumber);

遍历当前配置的接口
添加接口:device_add(&intf->dev)
重点:会触发probe

hub初始化过程

  1. 添加usb接口时(device_add)触发probe,如果接口是hub,则执行hub_probe

    hub的匹配表:USB_CLASS_HUB=9
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    static const struct usb_device_id hub_id_table[] = {
    { .match_flags = USB_DEVICE_ID_MATCH_VENDOR //指定产商的hub
    | USB_DEVICE_ID_MATCH_INT_CLASS,
    .idVendor = USB_VENDOR_GENESYS_LOGIC,
    .bInterfaceClass = USB_CLASS_HUB,
    .driver_info = HUB_QUIRK_CHECK_PORT_AUTOSUSPEND},
    { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS, //设备为hub
    .bDeviceClass = USB_CLASS_HUB},
    { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, //接口为hub
    .bInterfaceClass = USB_CLASS_HUB},
    { } /* Terminating entry */
    };
  2. hub_probe
    新建1个hub,配置hub(重点

    1
    2
    3
    4
    5
    hub = kzalloc(sizeof(*hub), GFP_KERNEL)
    ...
    INIT_WORK(&hub->events, hub_event);
    usb_set_intfdata (intf, hub);
    hub_configure(hub, endpoint)

hub_event是重点

配置hub

hub_configure(struct usb_hub hub, struct usb_endpoint_descriptor endpoint)

  1. 获取hub的描述
    get_hub_descriptor(hdev, hub->descriptor)

  2. 获取hub设备的状态
    usb_get_status(hdev, USB_RECIP_DEVICE, 0, &hubstatus)

  3. 获取hub的状态
    hub_hub_status(hub, &hubstatus, &hubchange)
    get_hub_status(hub->hdev, &hub->status->hub)

  4. 创建端口设备

    1
    2
    3
    4
    5
    6
    7
    8
    for (i = 0; i < maxchild; i++) {
    ret = usb_hub_create_port_device(hub, i + 1);
    if (ret < 0) {
    dev_err(hub->intfdev,
    "couldn't create port%d device.\n", i + 1);
    break;
    }
    }
    1
    2
    3
    4
    5
    6
    port_dev->dev.groups = port_dev_group;
    port_dev->dev.type = &usb_port_device_type;
    port_dev->dev.driver = &usb_port_driver;
    dev_set_name(&port_dev->dev, "%s-port%d", dev_name(&hub->hdev->dev),
    port1);
    retval = device_register(&port_dev->dev);

    创建的端口在/sys/bus/usb/device/下可见

hub事件处理

hub_event

处理hub下每个端口的事件

1
2
3
4
for (i = 1; i <= hdev->maxchild; i++) {
...
port_event(hub, i);
}

port_event
获取端口状态:hub_port_status(hub, port1, &portstatus, &portchange)
端口连接事件发生变化时,执行hub_port_connect_change

hub端口连接事件

hub_port_connect_change->hub_port_connect

  1. 端口下有设备,则先移除

    1
    2
    3
    4
    5
    if (udev) {
    if (hcd->usb_phy && !hdev->parent)
    usb_phy_notify_disconnect(hcd->usb_phy, udev->speed);
    usb_disconnect(&port_dev->child);
    }
  2. 创建一个usb设备
    udev = usb_alloc_dev(hdev, hdev->bus, port1)

  3. 初始化hub port
    hub_port_init(hub, udev, port1, i);
    获取设备描述:usb_get_device_descriptor(udev, USB_DT_DEVICE_SIZE)
  4. 添加usb设备
    status = usb_new_device(udev);